package ca.ericslandry.client.mvp.presenter;

import net.customware.gwt.dispatch.client.DispatchAsync;
import net.customware.gwt.presenter.client.EventBus;
import net.customware.gwt.presenter.client.place.Place;
import net.customware.gwt.presenter.client.place.PlaceRequest;
import ca.ericslandry.client.GwtCallback;
import ca.ericslandry.client.resource.MyConstants;
import ca.ericslandry.shared.domain.User;
import ca.ericslandry.shared.event.AuthenticationVerificationEvent;
import ca.ericslandry.shared.event.UserUpdatedEvent;
import ca.ericslandry.shared.rpc.GetUser;
import ca.ericslandry.shared.rpc.GetUserResult;
import ca.ericslandry.shared.rpc.UserSave;
import ca.ericslandry.shared.rpc.UserSaveResult;

import com.allen_sauer.gwt.log.client.Log;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.user.client.ui.Hyperlink;
import com.google.inject.Inject;

public class UserPresenter extends BasePresenter<UserPresenter.Display> {
	public interface Display extends BaseDisplay {
		HasClickHandlers getSave();

		User getUser();

		void editUser(User user);

		void viewUser(User user);
	}

	public static final Place PLACE = new Place("user");
	public static User currentUser;
	private final DispatchAsync dispatcher;
	private ContentPresenter contentPresenter;

	@Inject
	public UserPresenter(Display display, EventBus eventBus, DispatchAsync dispatcher, ContentPresenter contentPresenter) {
		super(display, eventBus);
		this.dispatcher = dispatcher;
		this.contentPresenter = contentPresenter;
		bind();
	}

	@Override
	protected void onBind() {
		Log.debug("onBind: user");
		// ACTION: Save user
		registerHandler(display.getSave().addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				User user = display.getUser();
				dispatcher.execute(new UserSave(user), new GwtCallback<UserSaveResult>(dispatcher, eventBus, display) {
					@Override
					public void callback(UserSaveResult result) {
						eventBus.fireEvent(new UserUpdatedEvent(result.getUser()));
					}
				});
				contentPresenter.getDisplay().pop();
			}
		}));
		// EVENT: user update
		registerHandler(eventBus.addHandler(AuthenticationVerificationEvent.TYPE,
				new AuthenticationVerificationEvent.Handler() {
					@Override
					public void onVerify(AuthenticationVerificationEvent event) {
						if (event.isVerified()) {
							Long userId = event.getUserId();
							dispatcher.execute(new GetUser(userId), new GwtCallback<GetUserResult>(dispatcher,
									eventBus, display) {
								@Override
								public void callback(GetUserResult result) {
									User user = result.getUser();
									if (user != null) {
										currentUser = user;
									}
								}
							});
						}
					}
				}));
	}

	@Override
	public Place getPlace() {
		return PLACE;
	}

	@Override
	protected void onPlaceRequest(PlaceRequest placeReq) {
		Log.info("onPlaceRequest : " + placeReq.getPlace().getId());
		String action = placeReq.getParameter(ACTION, null);
		if (VIEW.equalsIgnoreCase(action)) {
			viewUser(parseUserId(placeReq));
		} else if (UPDATE.equalsIgnoreCase(action)) {
			editUser(parseUserId(placeReq));
		} else {
			Log.warn("Bad placeRequest:" + placeReq.toString());
		}
	}

	private Long parseUserId(PlaceRequest placeReq) {
		Long retVal = null;
		try {
			retVal = Long.parseLong(placeReq.getParameter(ID, null));
		} catch (NumberFormatException e) {
			Log.warn("Problem with view user's ID", e);
		}
		return retVal;
	}

	public static boolean isLoggedin() {
		return currentUser != null;
	}

	private void viewUser(Long id) {
		Log.info("View user with ID: " + id);
		contentPresenter.getDisplay().setContent(display.asWidget());
		dispatcher.execute(new GetUser(id), new GwtCallback<GetUserResult>(dispatcher, eventBus, display) {
			@Override
			public void callback(GetUserResult result) {
				display.viewUser(result.getUser());
			}
		});
	}

	private void editUser(Long id) {
		Log.info("edit user with ID: " + id);
		contentPresenter.getDisplay().setContent(display.asWidget());
		dispatcher.execute(new GetUser(id), new GwtCallback<GetUserResult>(dispatcher, eventBus, display) {
			@Override
			public void callback(GetUserResult result) {
				display.editUser(result.getUser());
			}
		});
	}

	public static Hyperlink getLinkViewUser(User user) {
		PlaceRequest placeReq = new PlaceRequest(PLACE).with(ACTION, VIEW).with(ID, String.valueOf(user.getId()));
		String displayName = user.getDisplayName();
		if (displayName == null) {
			displayName = MyConstants.INSTANCE.unknown();
		} else if (displayName.startsWith("?")) {
			displayName = MyConstants.INSTANCE.unknown() + displayName.substring(1);
		}
		return new Hyperlink(displayName, placeReq.toString());
	}

	public static Hyperlink getLinkEditUser(User user) {
		PlaceRequest placeReq = new PlaceRequest(PLACE).with(ACTION, UPDATE).with(ID, String.valueOf(user.getId()));
		return new Hyperlink(MyConstants.INSTANCE.editUser(), placeReq.toString());
	}
}
